#!/usr/bin/env node

/**
 * 多任务并行循环爬取工具
 * 
 * 功能：支持多个任务同时运行，每个任务独立循环执行
 * 
 * 用法：
 *   node parallel-loop-crawler.js
 *   node parallel-loop-crawler.js --config loop-tasks.config.js
 *   node parallel-loop-crawler.js --tasks "amazon-jp,amazon-de"
 */

const { chromium } = require('playwright');
const { chromium: chromiumExtra } = require('playwright-extra');
const stealth = require('puppeteer-extra-plugin-stealth')();
const EcommerceCrawler = require('./ecommerce-crawler');
const config = require('./tasks.config');
const dbConnection = require('./db/connection');
const path = require('path');
const fs = require('fs');

// 任务状态
const TaskStatus = {
    IDLE: 'idle',           // 空闲
    RUNNING: 'running',     // 运行中
    WAITING: 'waiting',     // 等待中
    STOPPED: 'stopped',     // 已停止
    ERROR: 'error'          // 错误
};

// 单个循环任务管理器
class LoopTaskManager {
    constructor(taskName, taskConfig, options = {}) {
        this.taskName = taskName;
        this.taskConfig = taskConfig;
        this.options = {
            keywords: options.keywords || [],
            interval: options.interval || 3600,      // 循环间隔（秒）
            keywordDelay: options.keywordDelay || 5000,  // 关键词间延迟（毫秒）
            maxRetries: options.maxRetries || 3,     // 最大重试次数
            headless: options.headless !== undefined ? options.headless : false,
            slowMo: options.slowMo || 500,
            stealth: options.stealth !== undefined ? options.stealth : true,
            ...options
        };
        
        this.status = TaskStatus.IDLE;
        this.browser = null;
        this.currentKeywordIndex = 0;
        this.loopCount = 0;
        this.statistics = {
            totalRuns: 0,
            successRuns: 0,
            failedRuns: 0,
            totalKeywords: 0,
            successKeywords: 0,
            failedKeywords: 0,
            lastRunTime: null,
            lastSuccessTime: null,
            errors: []
        };
        
        this.shouldStop = false;
        this.startTime = Date.now();
    }

    /**
     * 启动任务循环
     */
    async start() {
        console.log(`\n🚀 [${this.taskName}] 任务启动`);
        console.log(`   关键词: ${this.options.keywords.length} 个`);
        console.log(`   循环间隔: ${this.options.interval} 秒`);
        
        this.shouldStop = false;
        
        // 连接数据库
        try {
            if (!dbConnection.isConnectionActive()) {
                await dbConnection.connect();
            }
        } catch (error) {
            console.error(`⚠️  [${this.taskName}] 数据库连接失败:`, error.message);
        }
        
        // 启动浏览器
        await this.initBrowser();
        
        // 开始循环
        await this.runLoop();
    }

    /**
     * 初始化浏览器
     */
    async initBrowser() {
        try {
            const launchOptions = {
                headless: this.options.headless,
                slowMo: this.options.slowMo
            };
            
            if (this.options.stealth) {
                chromiumExtra.use(stealth);
                this.browser = await chromiumExtra.launch(launchOptions);
            } else {
                this.browser = await chromium.launch(launchOptions);
            }
            
            console.log(`✅ [${this.taskName}] 浏览器启动成功`);
        } catch (error) {
            console.error(`❌ [${this.taskName}] 浏览器启动失败:`, error.message);
            throw error;
        }
    }

    /**
     * 运行循环
     */
    async runLoop() {
        while (!this.shouldStop) {
            this.loopCount++;
            this.status = TaskStatus.RUNNING;
            
            console.log(`\n🔄 [${this.taskName}] 开始第 ${this.loopCount} 次循环`);
            console.log(`   时间: ${new Date().toLocaleString('zh-CN')}`);
            
            const loopStartTime = Date.now();
            let loopSuccess = true;
            
            // 执行所有关键词
            for (let i = 0; i < this.options.keywords.length; i++) {
                if (this.shouldStop) break;
                
                const keyword = this.options.keywords[i];
                this.currentKeywordIndex = i;
                
                console.log(`\n   📝 [${this.taskName}] [${i + 1}/${this.options.keywords.length}] 关键词: "${keyword}"`);
                
                const keywordSuccess = await this.executeKeyword(keyword);
                
                this.statistics.totalKeywords++;
                if (keywordSuccess) {
                    this.statistics.successKeywords++;
                } else {
                    this.statistics.failedKeywords++;
                    loopSuccess = false;
                }
                
                // 关键词间延迟
                if (i < this.options.keywords.length - 1 && !this.shouldStop) {
                    await this.sleep(this.options.keywordDelay);
                }
            }
            
            const loopDuration = ((Date.now() - loopStartTime) / 1000).toFixed(2);
            
            this.statistics.totalRuns++;
            this.statistics.lastRunTime = new Date();
            
            if (loopSuccess) {
                this.statistics.successRuns++;
                this.statistics.lastSuccessTime = new Date();
                console.log(`\n✅ [${this.taskName}] 第 ${this.loopCount} 次循环完成 (耗时: ${loopDuration}秒)`);
            } else {
                this.statistics.failedRuns++;
                console.log(`\n⚠️  [${this.taskName}] 第 ${this.loopCount} 次循环完成，但有关键词失败 (耗时: ${loopDuration}秒)`);
            }
            
            // 打印统计
            this.printStatistics();
            
            // 等待下次循环
            if (!this.shouldStop) {
                this.status = TaskStatus.WAITING;
                const nextRunTime = new Date(Date.now() + this.options.interval * 1000);
                console.log(`\n⏰ [${this.taskName}] 等待 ${this.options.interval} 秒...`);
                console.log(`   下次执行时间: ${nextRunTime.toLocaleString('zh-CN')}`);
                
                await this.sleep(this.options.interval * 1000);
            }
        }
        
        // 清理
        await this.cleanup();
    }

    /**
     * 执行单个关键词
     */
    async executeKeyword(keyword) {
        let retries = 0;
        
        while (retries < this.options.maxRetries) {
            try {
                // 创建新页面
                const page = await this.browser.newPage();
                
                // 设置用户代理
                await page.setExtraHTTPHeaders({
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
                });

                // 创建爬虫实例
                const crawler = new EcommerceCrawler();
                crawler.browser = this.browser;
                crawler.page = page;

                // 设置环境变量（关键词）
                const originalKeyword = process.env.CRAWL_KEYWORD;
                process.env.CRAWL_KEYWORD = keyword;

                // 执行爬取
                if (typeof this.taskConfig.customCrawl === 'function') {
                    await this.taskConfig.customCrawl(page, crawler);
                } else {
                    await page.goto(this.taskConfig.url, {
                        waitUntil: 'networkidle',
                        timeout: this.taskConfig.crawlOptions?.timeout || 30000
                    });
                }

                // 恢复环境变量
                if (originalKeyword) {
                    process.env.CRAWL_KEYWORD = originalKeyword;
                } else {
                    delete process.env.CRAWL_KEYWORD;
                }

                // 关闭页面
                await page.close();

                console.log(`      ✅ 执行成功`);
                return true;

            } catch (error) {
                retries++;
                console.error(`      ❌ 执行失败 (尝试 ${retries}/${this.options.maxRetries}): ${error.message}`);
                
                this.statistics.errors.push({
                    keyword: keyword,
                    error: error.message,
                    timestamp: new Date().toISOString(),
                    retry: retries
                });
                
                if (retries < this.options.maxRetries) {
                    console.log(`      ⏳ ${3}秒后重试...`);
                    await this.sleep(3000);
                } else {
                    console.error(`      ❌ 达到最大重试次数，放弃`);
                    return false;
                }
            }
        }
        
        return false;
    }

    /**
     * 打印统计信息
     */
    printStatistics() {
        const runTime = ((Date.now() - this.startTime) / 1000 / 60).toFixed(2);
        const successRate = this.statistics.totalRuns > 0 
            ? ((this.statistics.successRuns / this.statistics.totalRuns) * 100).toFixed(2) 
            : 0;
        
        console.log(`\n📊 [${this.taskName}] 统计信息:`);
        console.log(`   运行时长: ${runTime} 分钟`);
        console.log(`   循环次数: ${this.statistics.totalRuns}`);
        console.log(`   成功次数: ${this.statistics.successRuns} (${successRate}%)`);
        console.log(`   失败次数: ${this.statistics.failedRuns}`);
        console.log(`   关键词总数: ${this.statistics.totalKeywords}`);
        console.log(`   关键词成功: ${this.statistics.successKeywords}`);
        console.log(`   关键词失败: ${this.statistics.failedKeywords}`);
        if (this.statistics.lastSuccessTime) {
            console.log(`   最后成功: ${this.statistics.lastSuccessTime.toLocaleString('zh-CN')}`);
        }
    }

    /**
     * 停止任务
     */
    async stop() {
        console.log(`\n🛑 [${this.taskName}] 收到停止信号`);
        this.shouldStop = true;
        this.status = TaskStatus.STOPPED;
    }

    /**
     * 清理资源
     */
    async cleanup() {
        try {
            if (this.browser) {
                await this.browser.close();
                console.log(`🔚 [${this.taskName}] 浏览器已关闭`);
            }
            this.status = TaskStatus.STOPPED;
        } catch (error) {
            console.error(`❌ [${this.taskName}] 清理失败:`, error.message);
        }
    }

    /**
     * 获取状态
     */
    getStatus() {
        return {
            taskName: this.taskName,
            status: this.status,
            loopCount: this.loopCount,
            currentKeywordIndex: this.currentKeywordIndex,
            statistics: this.statistics,
            runTime: ((Date.now() - this.startTime) / 1000 / 60).toFixed(2)
        };
    }

    /**
     * 延迟函数
     */
    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

// 多任务并行循环管理器
class ParallelLoopManager {
    constructor() {
        this.tasks = new Map();
        this.isRunning = false;
    }

    /**
     * 添加任务
     */
    addTask(taskName, taskConfig, options) {
        const taskManager = new LoopTaskManager(taskName, taskConfig, options);
        this.tasks.set(taskName, taskManager);
        console.log(`✅ 添加任务: ${taskName}`);
        return this;
    }

    /**
     * 启动所有任务
     */
    async startAll() {
        console.log('\n' + '='.repeat(80));
        console.log('🚀 多任务并行循环爬取器');
        console.log('='.repeat(80));
        console.log(`总任务数: ${this.tasks.size}`);
        console.log(`开始时间: ${new Date().toLocaleString('zh-CN')}`);
        console.log('='.repeat(80));
        
        this.isRunning = true;
        
        // 并行启动所有任务
        const taskPromises = Array.from(this.tasks.values()).map(task => 
            task.start().catch(error => {
                console.error(`❌ 任务 ${task.taskName} 启动失败:`, error.message);
            })
        );
        
        // 设置信号处理
        this.setupSignalHandlers();
        
        // 启动状态监控
        this.startMonitoring();
        
        // 等待所有任务
        await Promise.all(taskPromises);
        
        console.log('\n' + '='.repeat(80));
        console.log('✅ 所有任务已结束');
        console.log('='.repeat(80));
        
        // 关闭数据库连接
        if (dbConnection.isConnectionActive()) {
            await dbConnection.disconnect();
        }
    }

    /**
     * 停止所有任务
     */
    async stopAll() {
        console.log('\n🛑 停止所有任务...');
        
        const stopPromises = Array.from(this.tasks.values()).map(task => 
            task.stop().catch(error => {
                console.error(`❌ 停止任务 ${task.taskName} 失败:`, error.message);
            })
        );
        
        await Promise.all(stopPromises);
        this.isRunning = false;
    }

    /**
     * 获取所有任务状态
     */
    getAllStatus() {
        const statuses = {};
        this.tasks.forEach((task, name) => {
            statuses[name] = task.getStatus();
        });
        return statuses;
    }

    /**
     * 打印所有任务状态
     */
    printAllStatus() {
        console.log('\n' + '='.repeat(80));
        console.log('📊 所有任务状态');
        console.log('='.repeat(80));
        
        this.tasks.forEach((task, name) => {
            const status = task.getStatus();
            console.log(`\n📋 ${name}:`);
            console.log(`   状态: ${status.status}`);
            console.log(`   循环次数: ${status.loopCount}`);
            console.log(`   运行时长: ${status.runTime} 分钟`);
            console.log(`   成功率: ${status.statistics.totalRuns > 0 ? ((status.statistics.successRuns / status.statistics.totalRuns) * 100).toFixed(2) : 0}%`);
        });
        
        console.log('='.repeat(80));
    }

    /**
     * 设置信号处理器
     */
    setupSignalHandlers() {
        const handleExit = async (signal) => {
            console.log(`\n\n收到 ${signal} 信号，正在优雅退出...`);
            await this.stopAll();
            process.exit(0);
        };
        
        process.on('SIGINT', handleExit);
        process.on('SIGTERM', handleExit);
    }

    /**
     * 启动状态监控
     */
    startMonitoring() {
        // 每5分钟打印一次状态
        const monitorInterval = setInterval(() => {
            if (!this.isRunning) {
                clearInterval(monitorInterval);
                return;
            }
            this.printAllStatus();
        }, 5 * 60 * 1000);
    }
}

// 解析命令行参数
function parseArgs() {
    const args = process.argv.slice(2);
    const options = {
        configFile: null,
        tasks: null,
        help: false
    };
    
    for (let i = 0; i < args.length; i++) {
        const arg = args[i];
        
        if (arg === '--config' && i + 1 < args.length) {
            options.configFile = args[i + 1];
            i++;
        } else if (arg === '--tasks' && i + 1 < args.length) {
            options.tasks = args[i + 1].split(',').map(t => t.trim());
            i++;
        } else if (arg === '--help' || arg === '-h') {
            options.help = true;
        }
    }
    
    return options;
}

// 显示帮助信息
function showHelp() {
    console.log(`
多任务并行循环爬取工具

功能：
  支持多个任务同时运行，每个任务独立循环执行

用法：
  node parallel-loop-crawler.js [选项]

选项：
  --config <文件>    指定配置文件（默认：loop-tasks.config.js）
  --tasks <任务>     指定要运行的任务列表（逗号分隔）
  -h, --help         显示帮助信息

配置文件格式：
  module.exports = {
    tasks: {
      'amazon-jp': {
        keywords: ['ベビーフード', 'おむつ'],
        interval: 3600,        // 循环间隔（秒）
        keywordDelay: 5000,    // 关键词间延迟（毫秒）
        maxRetries: 3,         // 最大重试次数
        headless: false,
        stealth: true
      },
      'amazon-de': {
        keywords: ['Baby Foods', 'Toys'],
        interval: 7200,
        keywordDelay: 5000
      }
    }
  };

示例：
  # 使用默认配置
  node parallel-loop-crawler.js

  # 使用自定义配置文件
  node parallel-loop-crawler.js --config my-config.js

  # 只运行指定的任务
  node parallel-loop-crawler.js --tasks "amazon-jp,amazon-de"

注意：
  - 按 Ctrl+C 可以优雅停止所有任务
  - 每5分钟会自动打印所有任务状态
  - 配置文件请参考 loop-tasks.config.js.example
    `);
}

// 加载任务配置
function loadTaskConfig(taskName) {
    try {
        const taskPath = path.join(__dirname, 'tasks', taskName, 'index.js');
        if (!fs.existsSync(taskPath)) {
            throw new Error(`任务 "${taskName}" 不存在`);
        }
        return require(taskPath);
    } catch (error) {
        throw new Error(`加载任务 "${taskName}" 失败: ${error.message}`);
    }
}

// 主函数
async function main() {
    const options = parseArgs();
    
    if (options.help) {
        showHelp();
        return;
    }
    
    try {
        // 加载配置文件
        const configFile = options.configFile || 'loop-tasks.config.js';
        const configPath = path.join(__dirname, configFile);
        
        let loopConfig;
        if (fs.existsSync(configPath)) {
            loopConfig = require(configPath);
            console.log(`✅ 已加载配置文件: ${configFile}`);
        } else {
            console.log(`⚠️  配置文件不存在: ${configFile}`);
            console.log(`💡 将使用默认配置`);
            
            // 使用默认配置
            loopConfig = {
                tasks: {}
            };
            
            // 从 tasks.config.js 中读取关键词
            const taskNames = options.tasks || ['amazon-jp', 'amazon-de'];
            taskNames.forEach(taskName => {
                const keywords = config.keywords && config.keywords[taskName];
                if (keywords && keywords.length > 0) {
                    loopConfig.tasks[taskName] = {
                        keywords: keywords,
                        interval: 3600,
                        keywordDelay: 5000,
                        maxRetries: 3,
                        headless: false,
                        stealth: true
                    };
                }
            });
        }
        
        // 创建管理器
        const manager = new ParallelLoopManager();
        
        // 添加任务
        const tasksToRun = options.tasks || Object.keys(loopConfig.tasks);
        
        for (const taskName of tasksToRun) {
            const taskOptions = loopConfig.tasks[taskName];
            if (!taskOptions) {
                console.warn(`⚠️  任务 "${taskName}" 没有配置，跳过`);
                continue;
            }
            
            const taskConfig = loadTaskConfig(taskName);
            manager.addTask(taskName, taskConfig, taskOptions);
        }
        
        if (manager.tasks.size === 0) {
            console.error('❌ 没有要执行的任务');
            console.log('💡 请检查配置文件或使用 --help 查看帮助');
            process.exit(1);
        }
        
        // 启动所有任务
        await manager.startAll();
        
    } catch (error) {
        console.error('❌ 执行失败:', error.message);
        console.error('   详情:', error.stack);
        process.exit(1);
    }
}

// 运行
if (require.main === module) {
    main().catch(console.error);
}

module.exports = { ParallelLoopManager, LoopTaskManager };

